package de.ryancarmon.validator.validators;

import de.ryancarmon.validator.ValidatorParam;
import de.ryancarmon.validator.exc.CastingFailedException;
import de.ryancarmon.validator.exc.ParameterMissingException;

public abstract class BaseValidator<O> {

	public final void validate(O param, Object[] params) {
		for (int i = 0; i < params.length; i++) {
			ValidatorParam validate = castToParam(params[i]);
			boolean hasVar = validate.hasVar();
			boolean required = validate.isRequired();

			int next = i + 1;

			if (required && isParam(params[next]))
				throw new ParameterMissingException(validate);

			if (!hasVar || isParam(params[next]))
				executeValidation(param, validate);
			else {
				executeValidation(param, validate, params[next]);
				i++;
			}

		}
	}

	protected abstract void executeValidation(O param, ValidatorParam validation);

	protected abstract void executeValidation(O param,
			ValidatorParam validation, Object validParam);

	protected final ValidatorParam castToParam(Object param) {
		if (param == null)
			throw new IllegalArgumentException("'param' may not be null");

		ValidatorParam prm;

		try {
			prm = (ValidatorParam) param;
		} catch (ClassCastException exc) {
			throw new CastingFailedException(param, "ValidatorParam");
		}

		return prm;
	}

	protected final boolean isParam(Object param) {
		return (param instanceof ValidatorParam);
	}

	protected final int toInteger(Object param) {
		if (param == null)
			throw new IllegalArgumentException("'param' may not be null");

		try {
			return Integer.parseInt(param.toString());
		} catch (ClassCastException exc) {
			throw new CastingFailedException(param, "Integer");
		}
	}

	protected final double toDouble(Object param) {
		if (param == null)
			throw new IllegalArgumentException("'param' may not be null");

		try {
			return Double.parseDouble(param.toString());
		} catch (ClassCastException exc) {
			throw new CastingFailedException(param, "Double");
		}
	}

	protected final String toString(Object object) {
		if (object == null)
			return "null";

		return object.toString();
	}

	protected final Class<?> toClass(Object object) {
		if (object == null)
			throw new IllegalArgumentException("'object' may not be null");

		Class<?> casted = null;

		try {
			casted = (Class<?>) object;
		} catch (ClassCastException exc) {
			throw new CastingFailedException(object, "Class");
		}

		return casted;
	}
}
